package com.shaw.study.springx.aop;

import com.shaw.study.springx.annotation.Service;
import com.shaw.study.springx.beans.AopConfigDefinition;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by asus on 2018/5/6.
 */
public class AopProxy implements InvocationHandler {
    private Object target;

    private List<AopConfigDefinition> aopConfigs;

    public AopProxy(List<AopConfigDefinition> aopConfigs){
        this.aopConfigs = aopConfigs;
    }

    public Object getProxy(Object targetInstance){
        this.target = targetInstance;
        Class<?> clazz = target.getClass();
        if (targetInstance.getClass().isAnnotationPresent(Service.class)) {
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        }else{
            return targetInstance;
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object returnObject = null;
        AopConfigDefinition aopConfigDefinition = this.getAopConfigDefinition(method);
        //获取切面方法
        Method beforeAspect = aopConfigDefinition.getBeforeAspect();
        Method afterAspect = aopConfigDefinition.getAfterAspect();
        //获取方法所属类
        Class clazz = beforeAspect.getDeclaringClass();
        Object obj = clazz.newInstance();
        if(aopConfigDefinition!=null) {
            //方法前切面
            beforeAspect.invoke(obj, null);
        }
        //目标方法执行
        returnObject = method.invoke(target, args);
        if(aopConfigDefinition!=null) {
            //方法后切面
            afterAspect.invoke(obj, null);
        }

        return returnObject;
    }

    /**
     * 根据方法获取对应的切面
     * @param method
     * @return
     */
    private AopConfigDefinition getAopConfigDefinition(Method method){
        if(this.aopConfigs==null||this.aopConfigs.size()==0){
            return null;
        }
        for(AopConfigDefinition aopConfigDefinition:aopConfigs){
            Pattern pattern = aopConfigDefinition.getPointCut();
            //验证是否符合正则要求
            Matcher matcher = pattern.matcher(method.toString());
            if(matcher.matches()){
                return aopConfigDefinition;
            }

        }
        return null;
    }

    public Object getTarget(){
        return this.target;
    }

    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("public .* com\\.shaw\\.study\\.springx\\.aop\\..*AopProxy\\..*invoke\\(.*\\).*");
        Matcher matcher = pattern.matcher("public java.lang.Object com.shaw.study.springx.aop.AopProxy.invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[]) throws java.lang.Throwable");
        System.out.println(matcher.matches());
    }
}
